package org.stvd.common.workflow;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.FormService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Title WorkflowUtils
 * @Destribution 工作流工具类
 * @author houzx
 * @date 2020年10月28日
 */
public class WorkflowUtils {

    private static Logger logger = LoggerFactory.getLogger(WorkflowUtils.class);

    // public static ApplicationContext context = new
    // ClassPathXmlApplicationContext("06-activiti-config.xml");

    // private static ProcessEngine processEngine = (ProcessEngine)
    // context.getBean("processEngineFactory");
    private static ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    public static FormService getFormService() {
        return processEngine.getFormService();
    }

    public static RepositoryService getRepositoryService() {
        return processEngine.getRepositoryService();
    }

    /**
     * 流程发布
     * 
     * @param bpmnFileName
     *            bpmn文件名、路径
     */
    public static Deployment deploy(String name, String... resources) {
        logger.info("发布流程:{},{}", name, resources);

        RepositoryService repositoryService = processEngine.getRepositoryService();
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        if (name != null && !"".equals(name)) {
            deploymentBuilder.name(name);
        }
        for (String resource : resources) {
            deploymentBuilder.addClasspathResource(resource);
        }
        return deploymentBuilder.deploy();
    }

    /**
     * 删除所有部署的流程
     */
    public static void deleteAllDeployment() {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        for (Deployment Deployment : repositoryService.createDeploymentQuery().list()) {
            repositoryService.deleteDeployment(Deployment.getId(), true);
        }

    }

    /**
     * 删除部署的流程
     * 
     * @param deploymentId
     * @param cascade
     *            是否级联删除，true：是
     */
    public static void delDeployment(String deploymentId, boolean cascade) {
        logger.info("删除流程:{},{}", deploymentId, cascade);
        // 获取仓库服务对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 级联删除,会删除和当前规则相关的所有信息，包括历史
        repositoryService.deleteDeployment(deploymentId, cascade);
    }

    /**
     * 启动流程实例
     * 
     * @param processDefinitionKey
     * @param businessKey
     * @param variables
     * @return
     */
    public static ProcessInstance startInstanceByKey(String processDefinitionKey, String businessKey,
            Map<String, Object> variables) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey,
                variables);
        // logger.info("获取instance：" + instance);
        // logger.info("获取instance_ActivityId：" + instance.getActivityId());
        // logger.info("获取instance_DeploymentId：" + instance.getDeploymentId());
        // logger.info("获取instance_id：" + instance.getId());
        // logger.info("获取instance_ProcessInstanceId：" +
        // instance.getProcessInstanceId());
        // logger.info("获取instance_ProcessDefinitionId：" +
        // instance.getProcessDefinitionId());
        // logger.info("获取instance_ProcessDefinitionName：" +
        // instance.getProcessDefinitionName());
        // logger.info("获取instance_ProcessDefinitionKey：" +
        // instance.getProcessDefinitionKey());
        // logger.info("获取instance_BusinessKey：" + instance.getBusinessKey());
        // logger.info("获取instance_Name：" + instance.getName());
        // logger.info("获取instance_Description：" + instance.getDescription());
        // logger.info("获取instance_LocalizedName：" +
        // instance.getLocalizedName());
        // logger.info("获取instance_LocalizedDescription：" +
        // instance.getLocalizedDescription());
        // logger.info("获取instance_TenantId：" + instance.getTenantId());

        return instance;
    }

    /**
     * 通过ID查找ProcessInstanceId
     */
    public static ProcessInstance findProcessInstanceId(String processInstanceId) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
                .list();
        return (list.size() > 0) ? list.get(0) : null;
    }

    /**
     * 流程实例是否已经挂起
     */
    public static boolean isSuppended(String processInstanceId) {
        ProcessInstance instan = findProcessInstanceId(processInstanceId);
        return (instan != null) ? instan.isSuspended() : true;
    }

    /**
     * 删除流程实例
     * 
     * @param processInstanceId
     * @param deleteReason
     */
    public static void deleteProcessInstance(String processInstanceId, String deleteReason) {
        logger.info("删除流程实例:{},{}", processInstanceId, deleteReason);
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
    }

    /**
     * 获取流程图并 显示
     * 
     * @return
     * @throws Exception
     */
    public static InputStream findProcessPic(String procDefId) throws Exception {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId)
                .singleResult();
        String diagramResourceName = procDef.getDiagramResourceName();
        InputStream imageStream = repositoryService.getResourceAsStream(procDef.getDeploymentId(), diagramResourceName);
        return imageStream;
    }

    /**
     * 根据执行人查询任务
     * 
     * @return
     */
    public static List<Task> findTaskByAssignee(String assignee) {
        logger.info("开始查看任务...");
        /*
         * TaskService taskService = (TaskService) CommonUtil
         * .getBean("taskService");
         */
        TaskService taskService = processEngine.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(assignee).list();
        logger.info("任务个数:" + taskList.size());
        return taskList;
    }

    /**
     * 执行任务
     * 
     * @return
     */
    public static void takeCompleteTask(String taskid, Map<String, Object> variables) {
        TaskService taskService = processEngine.getTaskService();
        taskService.complete(taskid, variables);
    }

    /**
     * 查询所有任务
     */
    public static List<Task> findAllTask() {
        logger.info("开始查询当前任务");
        TaskService taskService = processEngine.getTaskService();
        List<Task> taskList = taskService.createTaskQuery().list();
        logger.info("任务个数:" + taskList.size());
        for (Task t : taskList) {
            logger.info("task_id:" + t.getId());
            logger.info("task_name:" + t.getName());
            logger.info("task_owner:" + t.getOwner());
            logger.info("task_ProcessInstanceId:" + t.getProcessInstanceId());
            logger.info("task_Assignee:" + t.getAssignee());
        }
        return taskList;
    }

    public static void renderForm(String taskId) {
        FormService formService = processEngine.getFormService();

        if (taskId != null) {
            Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
            System.out.println("表单内容---" + renderedTaskForm.toString());

        }
        Map<String, String> formProperties = new HashMap<String, String>();
        //
        formProperties.put("fp_startTime", "2017-03-22 00:00:00");
        formProperties.put("fp_endTime", "2017-03-29 00:00:00");
        formProperties.put("pass", "1");
        formService.submitTaskFormData(taskId, formProperties);
    }

    /**
     * 转换流程节点类型为中文说明
     *
     * @param type
     *            英文名称
     * @return 翻译后的中文名称
     */
    public static String parseToZhType(String type) {
        Map<String, String> types = new HashMap<String, String>();
        types.put("userTask", "用户任务");
        types.put("serviceTask", "系统任务");
        types.put("startEvent", "开始节点");
        types.put("endEvent", "结束节点");
        types.put("exclusiveGateway", "条件判断节点(系统自动根据条件处理)");
        types.put("inclusiveGateway", "并行处理任务");
        types.put("callActivity", "子流程");
        return types.get(type) == null ? type : types.get(type);
    }

    /**
     * 导出图片文件到硬盘
     *
     * @return 文件的全路径
     */
    public static String exportDiagramToFile(RepositoryService repositoryService, ProcessDefinition processDefinition,
            String exportDir) throws IOException {
        String diagramResourceName = processDefinition.getDiagramResourceName();
        String key = processDefinition.getKey();
        int version = processDefinition.getVersion();
        String diagramPath = "";

        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                diagramResourceName);
        byte[] b = new byte[resourceAsStream.available()];

        @SuppressWarnings("unused")
        int len = -1;
        resourceAsStream.read(b, 0, b.length);

        // create file if not exist
        String diagramDir = exportDir + "/" + key + "/" + version;
        File diagramDirFile = new File(diagramDir);
        if (!diagramDirFile.exists()) {
            diagramDirFile.mkdirs();
        }
        diagramPath = diagramDir + "/" + diagramResourceName;
        File file = new File(diagramPath);

        // 文件存在退出
        if (file.exists()) {
            // 文件大小相同时直接返回否则重新创建文件(可能损坏)
            logger.info("diagram exist, ignore... : {}", diagramPath);
            return diagramPath;
        } else {
            file.createNewFile();
        }

        logger.info("export diagram to : {}", diagramPath);

        // wirte bytes to file
        FileUtils.writeByteArrayToFile(file, b);
        return diagramPath;
    }

    
}
